package com.mrx.spring.example.service;

import cn.hutool.bloomfilter.BloomFilter;
import cn.hutool.bloomfilter.BloomFilterUtil;
import com.mrx.spring.example.advice.exceptions.UserNameExistsException;
import com.mrx.spring.example.model.converter.UserConverter;
import com.mrx.spring.example.model.dto.UserDTO;
import com.mrx.spring.example.model.po.UserPO;
import com.mrx.spring.example.model.vo.UserVO;
import com.mrx.spring.example.security.RedisTokenService;
import com.mrx.spring.security.exception.UserNotFoundException;
import org.hashids.Hashids;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Mr.X
 * @since 2023-10-16 16:16
 **/
@Service
public class UserService {

    @Resource
    private Hashids hashids;

    @Resource
    private UserConverter userConverter;

    @Resource
    private RedisTokenService redisTokenService;

    private static final int BLOOM_FILTER_MAX_SIZE = 1_0000_0000;
    /**
     * 使用 HuTool 创建 一个 bloomFilter, HuTool 的 bloomFilter 只支持 8 个 hash 函数
     */
    private static final BloomFilter bloomFilter = BloomFilterUtil.createBitSet(BLOOM_FILTER_MAX_SIZE, BLOOM_FILTER_MAX_SIZE, 8);

    private static final Map<String, UserPO> users = Stream.of(
            UserPO.of(1L, "admin", "admin", Set.of("/user/*")),
            UserPO.of(2L, "test", "test", Set.of("/user/whoAmi"))
    ).collect(Collectors.toMap(UserPO::getName, Function.identity()));

    @PostConstruct
    public void initBloomFilter() {
        listAllUsers().stream().map(UserPO::getName).forEach(bloomFilter::add);
    }

    public void register(UserVO user) {
        String userName = user.getName();
        // 布隆过滤器显示存在, 实际上可能并不存在, 所以这里需要通过数据库进行二次判断
        if (bloomFilter.contains(userName) && isUserNameExists(userName)) {
            throw new UserNameExistsException("用户名已存在");
        }
        insertUser(userConverter.vo2PO(user));
    }

    public String login(UserVO user) {
        String userName = user.getName();
        String userNotFound = "用户不存在或账号或密码错误";
        // 布隆过滤器显示不存在则一定不存在
        if (!bloomFilter.contains(userName)) {
            throw new UserNotFoundException(userNotFound);
        }
        UserPO userPO = Optional.ofNullable(users.get(userName))
                .filter(it -> it.getPassword().equals(user.getPassword()))
                .orElseThrow(() -> new UserNotFoundException(userNotFound));
        String token = hashids.encode(userPO.getId(), System.nanoTime());
        return redisTokenService.setTokenWithUser(token, userPO);
    }

    public UserDTO whoIsThat(Long userId) {
        return users.values().stream().filter(it -> it.getId().equals(userId)).findFirst()
                .map(userConverter::po2DTO)
                .orElseThrow(() -> new UserNotFoundException("用户不存在"));
    }

    public void insertUser(UserPO userPO) {
        users.put(userPO.getName(), userPO);
    }

    public List<UserPO> listAllUsers() {
        return new ArrayList<>(users.values());
    }

    public boolean isUserNameExists(String userName) {
        return listAllUsers().stream().anyMatch(it -> it.getName().equals(userName));
    }

}
